#pragma once

#include <iostream>

#include "ShmService.hpp"
#include "ShmMessageManager.hpp"
#include "MemoryPoolInterface.hpp"
#include "ShmMemoryPool.hpp"
#include "ShmServiceManger.hpp"
#include "DataStructureManager.hpp"
#include "ShmSharedPtrNode.hpp"


class SharedServer : public MemoryPoolInterface {
public:
    static const char* MESSAGE_FILE_NAME;

    // 获取单例实例的函数
    static SharedServer* GetInstance(bool mode = ShmService::SHM_CONNECT, std::string path = ShmService::SHM_PATH) {
        if (_instance == nullptr) {
            std::lock_guard<std::mutex> lock(_mutex);
            if (_instance == nullptr) {
                _instance = new SharedServer(path, mode);
                LOG_CYC(NORMAL, "创建 SharedServer 实例，模式: %s", mode == ShmService::SHM_CREATE ? "创建" : "连接");
            }
        }
        return _instance;
    }

    // 销毁单例实例的函数
    static void DestroyInstance() {
        std::lock_guard<std::mutex> lock(_mutex);
        if (_instance != nullptr) {
            delete _instance;
            _instance = nullptr;
            LOG_CYC(NORMAL, "销毁 SharedServer 实例", nullptr);
        }
    }

public:

    // void Run() {
    //     if (!_isMaster)
    //         LOG_CYC(WARNING, "不是共享内存主进程，无需执行Run()", nullptr);

    //     while (true) {
    //         OnceLoop();
    //     }
    // }

    // 申请共享内存块
    void* allocate(std::size_t size) override {
        LOG_CYC(_DEBUG, "申请内存，大小：%d", size);
        // 向主进程发送申请消息，阻塞直到主进程申请成功
        ShmMemoryBlock block = _shmMessageManager->AllocateMessage(size);
        // 检查分配的内存块属性
        if (block._shmID < 0 || block._shmPos < 0 || block._blockSize < 0) {
            LOG_CYC(ERROR, "分配的内存块属性错误, fileId : %d, Pos : %d, blockSize : %d", block._shmID, block._shmPos, block._blockSize);
            return nullptr;
        }

        return _allocate(block);
    }

    // 释放共享内存块
    void deallocate(void* ptr, std::size_t size = -1) override {
        ShmMemoryBlock block;
        _deallocate(ptr, block);

        // 通知这块内存我不用了
        _shmMessageManager->DeallocateMessage(block);

        LOG_CYC(NORMAL, "释放内存成功，地址: %p", ptr);
    }

    ShmSharedPtrNode* GetData(DataStructureBlock& dataBlock) {
        LOG_CYC(_DEBUG, "获取数据，name：%s", dataBlock.buffer);

        ShmMemoryBlock shmBlock = _shmMessageManager->GetDataMessage(dataBlock);
        if (shmBlock._shmID < 0 || shmBlock._shmPos < 0 || shmBlock._blockSize < 0) {
            LOG_CYC(ERROR, "获取数据失败, fileId : %d, Pos : %d, blockSize : %d", shmBlock._shmID, shmBlock._shmPos, shmBlock._blockSize);
            return nullptr;
        }

        return reinterpret_cast<ShmSharedPtrNode*>(_allocate(shmBlock));
    }

    void SetData(DataStructureBlock& dataBlock, ShmSharedPtrNode* node) {

    }

    // 子进程使用
    // 将内存块包装成托管节点
    ShmSharedPtrNode* NewShmSharedPtrNode(void* ptr) {
        // 获取用于包装的共享内存
        void* shmSharedPtrNodeMem = allocate(sizeof(ShmSharedPtrNode));

        std::lock_guard<std::mutex> lock(_mapMutex);

        // 获取被托管内存块的信息
        auto manageit = _Blocks->find(ptr);
        if (manageit == _Blocks->end()) {
            LOG_CYC(FATAL, "当前地址未注册为共享内存, ShmSharedPtrNode创建失败, ptr : %p", ptr);
            deallocate(shmSharedPtrNodeMem);
            std::exit(0);
        }

        // 查找托管节点的内存块信息
        auto myit = _Blocks->find(shmSharedPtrNodeMem);
        assert(myit != _Blocks->end());

        // 使用定位 new 初始化 ShmSharedPtrNode 对象
        return new (shmSharedPtrNodeMem) ShmSharedPtrNode(myit->second, manageit->second);
    }

    // 关闭 server
    void CloseServer() {
        delete _CorhShm;

        if (!_isMaster) {
            // 删除单例模式的共享内存文件管理组件
            ShmServiceManger::DestroyInstance();

            delete _Blocks;
        }

        LOG_CYC(NORMAL, "关闭服务器成功", nullptr);
    }

private:

    // 子进程通过内存块信息，挂载这块内存
    void* _allocate(ShmMemoryBlock& block) {
        LOG_CYC(_DEBUG, "收到已分配内存块信息，fileId：%d，pos：%d, blockSize：%d", block._shmID, block._shmPos, block._blockSize);

        std::lock_guard<std::mutex> lock(_mapMutex);

        // 通过返回的消息获取对应共享内存文件管理器
        ShmServiceNode* shmNode = _shmServerManger->GetShmNodeByFileId(block._shmID);
        if (shmNode == nullptr) {
            // 共享内存文件还未挂载到当前进程
            if (block._blockSize > MAX_BYTES * (NPAGES - 1)) {
                // 处理超过最大管理大小的共享内存文件
                shmNode = _shmServerManger->GetShmMemory(block._blockSize, block._shmID);
            }
            else {
                shmNode = _shmServerManger->GetShmMemory(MAX_BYTES * (NPAGES - 1), block._shmID);
            }

            if (shmNode == nullptr) {
                LOG_CYC(ERROR, "挂载共享内存文件失败，ShmFileId : %d", block._shmID);
                assert(shmNode != nullptr);
            }

            _ShmCount[block._shmID] = 0;
        }

        // 获取这块共享内存文件首地址
        void* headPtr = shmNode->_shmSvr->GetShmHeader();
        if (headPtr == nullptr) {
            LOG_CYC(ERROR, "无效的共享内存文件首地址", nullptr);
            return nullptr;
        }

        void* retPtr = reinterpret_cast<void*>(reinterpret_cast<char*>(headPtr) + block._shmPos);

        (*_Blocks)[retPtr] = block;
        _ShmCount[block._shmID]++;

        return retPtr;
    }

    // 子进程释放指定内存块，回传释放内存块的信息
    void _deallocate(void* ptr, ShmMemoryBlock& block) {
        std::lock_guard<std::mutex> lock(_mapMutex);
        auto it = _Blocks->find(ptr);
        if (it == _Blocks->end()) {
            LOG_CYC(FATAL, "释放共享内存失败, 当前地址未注册为共享内存, ptr : %p", ptr);
            exit(0);
        }

        // 先去除当前进程共享文件连接
        block = it->second;
        _ShmCount[block._shmID]--;
        if (_ShmCount[block._shmID] == 0) {
            _shmServerManger->ReleaseShmMemory(block._shmID);
        }
        _Blocks->erase(ptr);
    }

private:

    // 主进程server循环
    void OnceLoop() {
        // 从队列中获取消息节点
        ShmMessageNode* mesNode = _shmMessageManager->GetMessageNodeFromQueue();
        if (mesNode == nullptr) {
            LOG_CYC(ERROR, "获取消息节点失败", nullptr);
            return;
        }

        switch (mesNode->GetFunctionType()) {
            case ShmFunctionType::AllocateSharedMemory:
                LOG_CYC(NORMAL, "处理申请消息", nullptr);
                AllocateSharedMemory(mesNode);
                break;

            case ShmFunctionType::ReleaseSharedMemory:
                LOG_CYC(NORMAL, "处理释放消息", nullptr);
                ReleaseSharedMemory(mesNode);
                break;

            case ShmFunctionType::DataStructure:
                LOG_CYC(NORMAL, "处理数据结构操作", nullptr);
                DataDataStructureOperate(mesNode);
                break;

            default:
                LOG_CYC(WARNING, "消息节点返回空功能类型", nullptr);
                break;
        }
    }

    // 主进程分配进程所需的内存块
    void AllocateSharedMemory(ShmMessageNode*& mesNode) {
        ShmScopedLock lock(mesNode->GetMutex());

        // 获取子进程申请共享内存的大小
        size_t allocSize = mesNode->GetSize();

        // 主进程获取对齐大小后的内存块
        size_t backSize = SizeClass::RoundUp(allocSize);
        void* ptr = _memoryPool->Allocate(backSize);
        if (ptr == nullptr) {
            LOG_CYC(ERROR, "共享内存分配失败", nullptr);

            // 设置申请失败消息
            mesNode->SetExecuteSuccess(false);

            // 通知子进程
            mesNode->Signal();

            // 由子进程释放消息节点
            return;
        }
        // 记录所获取共享内存块在共享内存文件中的位置
        mesNode->SetShmMemoryBlock(ObjFile(ptr), ObjPos(ptr), backSize);
        mesNode->SetExecuteSuccess(true);

        // 通知子进程
        mesNode->Signal();

        LOG_CYC(NORMAL, "申请成功，唤醒申请进程, fileId：%d, pos：%d, blockSize：%d", ObjFile(ptr), ObjPos(ptr), backSize);
    }

    // 主进程回收进程解除的内存块
    void ReleaseSharedMemory(ShmMessageNode*& mesNode) {
        // 获取子进程释放内存块所在共享内存文件和偏移量
        int shmFileId = mesNode->GetShmMemoryBlock()._shmID;
        int pos = mesNode->GetShmMemoryBlock()._shmPos;
        LOG_CYC(_DEBUG, "释放, fileId: %d, pos：%d", shmFileId, pos);

        // 执行释放功能，由主进程释放消息节点
        _shmMessageManager->GetMessagePool().Delete(mesNode);
        _memoryPool->Deallocate(shmFileId, pos);

        LOG_CYC(_DEBUG, "成功释放，FileId：%d，Pos：%d", shmFileId, pos);
    }

    // 主进程执行数据结构操作
    void DataDataStructureOperate(ShmMessageNode*& mesNode) {
        ShmScopedLock lock(mesNode->GetMutex());

        // 执行数据结构操作
        _dataStructureManager->Execute(mesNode);

        // 唤醒等待进程
        mesNode->Signal();
    }

private:
    SharedServer(std::string path, bool mode)
        :_isMaster(mode)
        , _path(path) {
        if (_isMaster) {
            std::string rmPath = "rm -rf /dev/shm/" + path + "*";
            int ret = system(rmPath.c_str());
        }

        // 初始化进程间交互的消息队列
        InitShmMessageManager();

        // 获取共享内存文件管理器
        _shmServerManger = ShmServiceManger::GetInstance(_path);

        // 初始化共享内存池
        if (_isMaster) {
            _memoryPool = ShmMemoryPool::GetInstance();
            _dataStructureManager = DataStructureManager::GetInstance();
        }

        if (!_isMaster) {
            _Blocks = new std::unordered_map<void*, ShmMemoryBlock>;
            _ShmCount.resize(MAX_SHM_COUNT, 0);
        }
        LOG_CYC(NORMAL, "初始化服务器成功", nullptr);

        while (_isMaster) {
            OnceLoop();
        }
    }

    ~SharedServer() {
        CloseServer();
    }

    // 禁止拷贝构造和赋值
    SharedServer(const SharedServer&) = delete;
    SharedServer& operator=(const SharedServer&) = delete;

    // 创建/连接 shm 消息管理器
    void InitShmMessageManager() {
        // 拼接共享内存文件名
        std::string shmFileName = _path + MESSAGE_FILE_NAME;

        // 挂载到当前进程
        _CorhShm = ShmService::ShmServicePOSIX::GetInstance(sizeof(ShmMessageManager), _isMaster, shmFileName.c_str());

        // 获取共享内存头部指针
        void* shmHeader = _CorhShm->GetShmHeader();
        if (shmHeader == nullptr) {
            LOG_CYC(ERROR, "核心组件初始化失败", nullptr);
        }

        if (_isMaster) {
            _shmMessageManager = new (shmHeader) ShmMessageManager();
        }
        else {
            _shmMessageManager = reinterpret_cast<ShmMessageManager*>(shmHeader);
        }
    }


private:

    // 共有部分
    bool _isMaster; // 是否为创建共享内存的进程
    std::string _path;
    ShmService::ShmServicePOSIX* _CorhShm = nullptr;    // 核心交互共享内存组件
    ShmMessageManager* _shmMessageManager = nullptr;    // 消息管理器
    ShmServiceManger* _shmServerManger = nullptr;       // 共享内存文件管理组件

    // 主进程拥有
    ShmMemoryPool* _memoryPool = nullptr;
    DataStructureManager* _dataStructureManager = nullptr;

    // 子进程拥有
    std::unordered_map<void*, ShmMemoryBlock>* _Blocks = nullptr;   // 记录当前子进程使用的共享内存块信息与地址映射            
    std::vector<uint32_t> _ShmCount;                                // 记录每个共享内存文件被当前子进程使用的内存块数量

    std::mutex _mapMutex; // 保护映射的互斥锁

    static SharedServer* _instance; // 单例实例
    static std::mutex _mutex; // 单例互斥锁
};

// 静态成员变量的定义和初始化
SharedServer* SharedServer::_instance = nullptr;
std::mutex SharedServer::_mutex;

const char* SharedServer::MESSAGE_FILE_NAME = "_message";